package com.xlf.service.judge.strategy.judgeProblemMode;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.xlf.common.core.exception.BizException;
import com.xlf.pojo.base.Judge;
import com.xlf.pojo.base.JudgeCase;
import com.xlf.pojo.constant.Constants;
import com.xlf.pojo.base.Problem;
import com.xlf.pojo.dto.RunResult;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;

/**
 * @Author xlf 2734029211@qq.com
 * @Date 2023/9/21 10:53
 * @Description: TODO
 * @Version 1.0
 */
public abstract class AbstractJudgeProblemModeStrategy {


    private final static Pattern EOL_PATTERN = Pattern.compile("[^\\S\\n]+(?=\\n)");


    /**
     * IOI ACM判题
     * @param problem
     * @param judge
     * @param judgeCases
     */
    public void Judge(Problem problem, Judge judge, List<JudgeCase> judgeCases) {

        Assert.notEmpty(judgeCases,() -> new BizException("judgeCases is null !"));

        //判题花费的时间和内存为各个测试用例的最大值
        Optional<Integer> maxMemory = judgeCases.stream().map(JudgeCase::getMemory).max(Integer::compare);
        Optional<Integer> maxTime = judgeCases.stream().map(JudgeCase::getTime).max(Integer::compare);
        judge.setTime(maxTime.get());
        judge.setMemory(maxMemory.get());

        final AtomicReference<Integer> status = new AtomicReference<>(Constants.Judge.STATUS_ACCEPTED.getStatus());

        AtomicBoolean wrongAnswer = new AtomicBoolean(false);
        Integer total = 0;
        Integer ioSource = 0;

        for (int i = 0; i < judgeCases.size(); i++) {

            JudgeCase item = judgeCases.get(i);
            ioSource += item.getScore();
            // 如果测试跑题无异常
            if (item.getStatus().equals(Constants.Judge.STATUS_ACCEPTED.getStatus())) {

                //时间超限
                if(item.getTime() > problem.getTimeLimit()){

                    item.setStatus(Constants.Judge.STATUS_TIME_LIMIT_EXCEEDED.getStatus());

                    //跑题出现异常,可能是运行错误、内存超限、时间超限。取第一个测试用例的结果就行
                    if(status.get().equals(Constants.Judge.STATUS_ACCEPTED.getStatus()))
                        status.set(item.getStatus());

                    //该测试点不得分
                    item.setScore(0);
                    continue;
                }
                // 与原测试数据输出的md5进行对比 AC或者是WA
                Integer integer = compareOutput(item.getUserOutput(), problem.getIsRemoveEndBlank(), item.getOutputData());
                //重新设置状态A
                item.setStatus(integer);
                if(integer.equals(Constants.Judge.STATUS_ACCEPTED.getStatus())) //该测试用例得分
                    total += item.getScore();
                else{
                    wrongAnswer.set(true);  //答案错误
                    //该测试点不得分
                    item.setScore(0);
                }
            } else {
                //跑题出现异常,可能是运行错误、内存超限、时间超限。取第一个测试用例的结果就行
                if(status.get().equals(Constants.Judge.STATUS_ACCEPTED.getStatus()))
                    status.set(item.getStatus());
                //该测试点不得分
                item.setScore(0);
            }
        }
        //如果存在答案错误那么最终的结果就是答案错误
        if(wrongAnswer.get())
            judge.setStatus(Constants.Judge.STATUS_WRONG_ANSWER.getStatus());
        else  //如果不存在那么可能全都是内存超限、时间超限。
            judge.setStatus(status.get());

        //最终得分
        judge.setScore(total);
        //总分
        judge.setOiRankScore(Math.max(ioSource, problem.getIoScore()));

    }


    public Integer TestJudge(String userOutput, Integer isRemoveEOLBlank, String testcase){
        return compareOutput(userOutput,isRemoveEOLBlank,testcase);
    }


    protected abstract Integer compareOutput(String userOutput, Integer isRemoveEOLBlank, String testcase);


    // 去除行末尾空白符
    protected String rtrim(String value) {
        if (value == null) return null;
        return EOL_PATTERN.matcher(StrUtil.trimEnd(value)).replaceAll("");
    }


}
